package com.zenus.monitor.aspect;

import com.zenus.monitor.annotation.ZeusCounter;
import com.zenus.monitor.annotation.ZeusTimer;
import com.zenus.monitor.metrics.ZeusMetrics;
import io.micrometer.core.instrument.Timer;
import io.prometheus.client.Counter;
import io.prometheus.client.Gauge;
import io.prometheus.client.Summary;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.lang.reflect.Method;

/**
 * @author magic
 * @date 2018/11/8/008 15:22
 * @version 1.0
 * Description PrometheusAspect
 */
@Aspect
public class PrometheusAspect {

    @Autowired
    ZeusMetrics zeusMetrics;


    private static final String COUNTER_SUCCESS_STATUS = "success";
    private static final String COUNTER_FAIL_STATUS = "fail";

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Around("@annotation(com.zenus.monitor.annotation.ZeusCounter)")
    public Object doAroundCounter(ProceedingJoinPoint joinPoint) throws Throwable{
        logger.info("doAroundCounter: {}",joinPoint);
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        ZeusCounter zeusCounter = method.getAnnotation(ZeusCounter.class);
        Counter counter =  zeusMetrics.getOrInitCounter(zeusCounter);
        try {
            Object result = joinPoint.proceed(joinPoint.getArgs());
            counter.labels(COUNTER_SUCCESS_STATUS).inc();
            return result;
        }catch (Throwable e){
            counter.labels(COUNTER_FAIL_STATUS).inc();
            throw e;
        }
    }

    @Around("@annotation(com.zenus.monitor.annotation.ZeusTimer)")
    public Object doAroundTimer(ProceedingJoinPoint joinPoint) throws Throwable{
        logger.info("doAroundTimer: {}",joinPoint);
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        ZeusTimer zeusTimer = method.getAnnotation(ZeusTimer.class);
        Summary summary  = zeusMetrics.getOrInitTimer(zeusTimer);
        Summary.Timer timer = summary.startTimer();
        try {
            Object result = joinPoint.proceed(joinPoint.getArgs());
            return result;
        }catch (Throwable e){
            throw  e;
        }finally {
            timer.observeDuration();
        }
    }



}
